"""
DeepSeek AI 文本润色模块
"""
import os
import re
import logging
import time
from typing import Optional, Dict
import requests

logger = logging.getLogger(__name__)


class TextPolisher:
    """文本润色器"""

    # 默认提示词模板
    DEFAULT_PROMPT_TEMPLATE = """你正在处理一段视频转录文本。这是语音识别系统自动生成的结果，可能存在识别错误、缺少标点、没有分段等问题。

{context_info}【重要说明】
- 这是转录结果，不是手写文本
- 主要任务是**还原说话者的原意**，修正识别错误
- 保持口语风格和说话习惯
- 不要过度书面化或改变表达方式

【润色要求】
1. 修正明显的语音识别错误（如同音字、错别字）
2. 添加合适的标点符号（句号、逗号、问号等）
3. 合理分段，每段2-4句话
4. **严格保持原意**，不添加、不删减、不改写内容
5. 保留口语化表达（如"嗯"、"啊"、"那个"可适当保留）
6. 如果有重复或啰嗦的地方，保留原貌

【原始转录文本】
{raw_text}

【输出格式】
请按以下JSON格式返回：
```json
{{
  "polished_text": "润色后的文本",
  "quality_score": 85,
  "explanation": "简短说明（可选，1-2句话）"
}}
```

quality_score 评分标准（0-100）：
- 90-100: 原文质量很好，几乎无需修改
- 70-89: 做了必要的修正和标点添加
- 50-69: 有较多识别错误需要修正
- 30-49: 识别错误较多，部分语义难以还原
- 0-29: 识别质量很差，难以理解原意

请只返回JSON，不要添加其他内容。"""

    def __init__(self, config: Dict):
        """
        初始化润色器

        Args:
            config: 润色配置
                - api_key: DeepSeek API密钥
                - base_url: API基础URL
                - model: 模型名称
                - fallback_model: 降级模型（可选）
                - timeout: 超时时间
                - prompt_template: 自定义提示词模板（可选）
        """
        self.api_key = config.get('api_key')
        self.base_url = config.get('base_url', 'https://api.deepseek.com')
        self.model = config.get('model', 'deepseek-chat')
        self.timeout = config.get('timeout', 90)  # 增加到90秒，适应长文本
        self.retry_times = config.get('retry_times', 2)  # 重试次数

        # 获取自定义模板，空字符串或None都使用默认模板
        custom_template = config.get('prompt_template', '')
        self.prompt_template = custom_template if custom_template else self.DEFAULT_PROMPT_TEMPLATE

        if not self.api_key:
            raise ValueError("DeepSeek API密钥未配置")

        # 如果提供了自定义模板，记录日志
        if custom_template:
            logger.info("使用自定义润色提示词模板")
        else:
            logger.debug("使用默认润色提示词模板")

    def polish(
        self, raw_text: str, context: Optional[Dict] = None, model: Optional[str] = None
    ) -> Optional[Dict]:
        """
        润色文本，使用指定模型（单次调用，不自动降级）

        Args:
            raw_text: 原始文本
            context: 上下文信息（可选），包含：
                - title: 作品标题
                - author: 作者
                - platform: 平台
                - keyword: 搜索关键词
            model: 指定使用的模型（可选，默认使用配置的主模型）

        Returns:
            润色结果字典，包含：
            - polished_text: 润色后的文本
            - status: 状态码 (1=成功, 2=失败)
            - error: 错误信息（如果失败）
            - used_model: 实际使用的模型
            - api_response: API 原始响应（失败时用于调试）
        """
        if not raw_text or not raw_text.strip():
            return {
                'polished_text': None,
                'status': 2,
                'error': '原始文本为空',
                'used_model': model or self.model,
                'api_response': None,
            }

        # 使用指定模型或默认模型
        target_model = model or self.model
        result = self._polish_with_model(raw_text, context, target_model)

        return result

    def _polish_with_model(
        self, raw_text: str, context: Optional[Dict], model: str
    ) -> Dict:
        """
        使用指定模型进行润色

        Args:
            raw_text: 原始文本
            context: 上下文信息
            model: 模型名称

        Returns:
            润色结果字典
        """
        api_response = None  # 保存 API 响应用于错误日志

        try:
            prompt = self._build_prompt(raw_text, context)

            # 临时切换模型
            original_model = self.model
            self.model = model
            api_response = self._call_api(prompt)
            self.model = original_model  # 恢复原模型

            # 尝试解析 JSON 响应
            result = self._parse_response(api_response)

            return {
                'polished_text': result['polished_text'],
                'status': 1,
                'error': None,
                'quality_score': result['quality_score'],
                'explanation': result.get('explanation', ''),
                'used_model': model,  # 记录实际使用的模型
                'api_response': api_response,  # 保存原始响应
            }

        except Exception as e:
            logger.error(f"润色失败: {str(e)}")

            # 打印详细的错误信息，方便调试
            logger.error("=" * 80)
            logger.error("润色失败详情")
            logger.error("=" * 80)
            logger.error(f"错误类型: {type(e).__name__}")
            logger.error(f"错误信息: {str(e)}")
            logger.error("-" * 80)
            logger.error(f"原始文本长度: {len(raw_text)} 字符")
            logger.error(f"原始文本 (前500字符):")
            logger.error(raw_text[:500] if raw_text else "N/A")
            if len(raw_text) > 500:
                logger.error(f"... (剩余 {len(raw_text) - 500} 字符)")
            logger.error("-" * 80)

            # 打印 API 响应（如果有）
            if api_response is not None:
                logger.error(f"API 返回内容长度: {len(api_response)} 字符")
                logger.error(f"API 返回内容 (前1000字符):")
                logger.error(api_response[:1000] if api_response else "(空响应)")
                if len(api_response) > 1000:
                    logger.error(f"... (剩余 {len(api_response) - 1000} 字符)")
            else:
                logger.error("API 响应: (未获取到响应，可能在调用前就失败了)")

            logger.error("=" * 80)

            return {
                'polished_text': None,
                'status': 2,
                'error': str(e),
                'quality_score': 0,
                'used_model': model,
                'api_response': api_response,  # 保存原始响应用于调试
            }

    def _build_prompt(
        self, raw_text: str, context: Optional[Dict] = None
    ) -> str:
        """
        构建润色提示词

        支持的模板变量：
            - {raw_text}: 原始转录文本
            - {context_info}: 自动生成的上下文信息
            - {title}: 作品标题
            - {author}: 作者
            - {keyword}: 搜索关键词
            - {platform}: 平台名称
            - {platform_code}: 平台代码（0/1/2）
        """
        # 准备上下文变量
        template_vars = {
            'raw_text': raw_text,
            'title': '',
            'author': '',
            'keyword': '',
            'platform': '未知',
            'platform_code': '',
        }

        # 构建context_info
        context_info = ""
        if context:
            context_parts = []
            if context.get('title'):
                template_vars['title'] = context['title']
                context_parts.append(f"标题：{context['title']}")
            if context.get('author'):
                template_vars['author'] = context['author']
                context_parts.append(f"作者：{context['author']}")
            if context.get('keyword'):
                template_vars['keyword'] = context['keyword']
                context_parts.append(f"关键词：{context['keyword']}")
            if context.get('platform') is not None:
                platform_map = {0: 'B站', 1: '抖音', 2: '小红书'}
                platform_name = platform_map.get(context['platform'], '未知')
                template_vars['platform'] = platform_name
                template_vars['platform_code'] = str(context['platform'])
                context_parts.append(f"平台：{platform_name}")

            if context_parts:
                context_info = f"""【视频信息】
{chr(10).join(context_parts)}

"""

        template_vars['context_info'] = context_info

        # 使用模板替换变量
        try:
            prompt = self.prompt_template.format(**template_vars)
        except KeyError as e:
            logger.warning(f"模板变量未定义: {e}，使用默认模板")
            # 降级到默认模板
            prompt = self.DEFAULT_PROMPT_TEMPLATE.format(**template_vars)

        return prompt

    def _call_api(self, prompt: str) -> str:
        """
        调用 DeepSeek API，支持重试机制

        Args:
            prompt: 提示词

        Returns:
            润色后的文本
        """
        url = f"{self.base_url}/chat/completions"
        headers = {
            'Authorization': f'Bearer {self.api_key}',
            'Content-Type': 'application/json',
        }
        data = {
            'model': self.model,
            'messages': [{'role': 'user', 'content': prompt}],
            'temperature': 0.3,  # 较低的温度，保持一致性
            'max_tokens': 4096,
        }

        logger.debug(f"调用DeepSeek API: {url}, timeout={self.timeout}s")

        last_error = None
        for attempt in range(self.retry_times + 1):
            try:
                if attempt > 0:
                    wait_time = 2 ** attempt  # 指数退避: 2s, 4s, 8s
                    logger.info(f"等待 {wait_time}s 后重试 (第{attempt}/{self.retry_times}次)")
                    time.sleep(wait_time)

                response = requests.post(
                    url, json=data, headers=headers, timeout=self.timeout
                )

                if response.status_code != 200:
                    raise Exception(
                        f"API调用失败: HTTP {response.status_code} - {response.text}"
                    )

                result = response.json()

                if 'choices' not in result or len(result['choices']) == 0:
                    logger.error(f"API返回格式错误，缺少 choices 字段: {result}")
                    raise Exception(f"API返回格式错误: {result}")

                content = result['choices'][0]['message'].get('content', '').strip()

                # 检查返回内容是否为空
                if not content:
                    logger.error(f"API 返回空内容，完整响应: {result}")
                    raise Exception("API 返回内容为空")

                polished_text = content

                if attempt > 0:
                    logger.info(f"重试成功 (第{attempt}次)")

                logger.debug(f"API 返回内容长度: {len(polished_text)} 字符")

                return polished_text

            except requests.exceptions.Timeout as e:
                last_error = f"请求超时 (timeout={self.timeout}s): {str(e)}"
                logger.warning(f"第{attempt + 1}次尝试失败: {last_error}")
            except requests.exceptions.ConnectionError as e:
                last_error = f"连接错误: {str(e)}"
                logger.warning(f"第{attempt + 1}次尝试失败: {last_error}")
            except Exception as e:
                last_error = str(e)
                logger.warning(f"第{attempt + 1}次尝试失败: {last_error}")
                # 对于非网络错误，不重试
                if attempt == 0 and 'HTTP' in str(e):
                    break

        # 所有重试都失败
        raise Exception(f"API调用失败 (已重试{self.retry_times}次): {last_error}")

    def _parse_response(self, api_response: str) -> Dict:
        """
        解析 AI 返回的 JSON 响应

        Args:
            api_response: AI API 返回的文本

        Returns:
            包含 polished_text, quality_score, explanation 的字典
        """
        import json

        # 尝试提取 JSON（可能包含在 markdown 代码块中）
        json_text = api_response.strip()

        # 移除可能的 markdown 代码块标记
        if json_text.startswith('```'):
            # 找到第一个 { 和最后一个 }
            start = json_text.find('{')
            end = json_text.rfind('}')
            if start != -1 and end != -1:
                json_text = json_text[start : end + 1]

        try:
            data = json.loads(json_text)

            # 验证必需字段
            if 'polished_text' not in data:
                raise ValueError("响应中缺少 polished_text 字段")

            # 确保 quality_score 在有效范围内
            quality_score = data.get('quality_score', 70)
            quality_score = max(0, min(100, int(quality_score)))

            return {
                'polished_text': data['polished_text'],
                'quality_score': quality_score,
                'explanation': data.get('explanation', ''),
            }

        except (json.JSONDecodeError, ValueError) as e:
            logger.warning(f"JSON 解析失败: {e}")

            # 检查响应是否为空或过短
            if not api_response or len(api_response.strip()) < 10:
                logger.error(f"API 返回空响应或过短内容: {repr(api_response[:100])}")
                raise ValueError(f"API 返回无效响应: {e}")

            # 降级策略：将整个响应作为润色文本，给一个默认评分
            logger.warning("使用降级策略：直接使用 API 原始响应")
            return {
                'polished_text': api_response,
                'quality_score': 60,  # 默认评分
                'explanation': 'AI 未返回标准格式',
            }


def load_env_config() -> Dict:
    """
    从环境变量加载配置

    Returns:
        配置字典
    """
    from dotenv import load_dotenv

    load_dotenv()

    return {
        'api_key': os.getenv('DEEPSEEK_API_KEY'),
        'base_url': os.getenv(
            'DEEPSEEK_BASE_URL', 'https://api.deepseek.com'
        ),
        'model': os.getenv('DEEPSEEK_MODEL', 'deepseek-chat'),  # 默认使用对话模型（快）
        'timeout': int(os.getenv('DEEPSEEK_TIMEOUT', '90')),  # 默认90秒
        'retry_times': int(os.getenv('DEEPSEEK_RETRY_TIMES', '2')),  # 默认重试2次
    }
